/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#include "stdafx.h"
#include <pgl/core/pgl.h>
#include <pgl/core/PGLMarker.h>
#include <pgl/core/PGLRegion.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif



PGL_IMPLEMENT_DYNCREATE(CPGLMarker,CPGLObject);
PGL_IMPLEMENT_SCRIPTING(Marker);

float CPGLMarker::m_fstLegendRadius=3.5;

#ifdef _DEBUG
void CPGLMarker::Dump( CDumpContext& dc ) const
{
    // call base class function first
    CPGLObject::Dump( dc );

    // now do the stuff for our specific class
	dc << _T("--- CPGLMarker ID ") << GetID() <<_T(" ---\n");
}

void CPGLMarker::AssertValid() const
{
    // call inherited AssertValid first
    CPGLObject::AssertValid();
} 
#endif

void CPGLMarker::SerializeXML(CPGLArchive& ar)
{
	static const TCHAR szTag[] = _T("CPGLMarker");

	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());
	if(ar.IsStoring())
	{
		xml.AddChildElem(szTag);
		xml.IntoElem();

			/////////////////////////////////////////////////////////
			// Adding base class
			CPGLObject::SerializeXML(ar);

			xml.AddChildElemEx(_T("LineWidth"), m_dLineWidth);
			xml.AddChildElemEx(_T("LineDashing"),m_sLineDashing);
			xml.AddChildElemEx( _T("Radius"), m_dRadius );
			xml.AddChildElemEx( _T("Phase"), m_dPhase );
			xml.AddChildElemEx(_T("Filled"), m_bFilled);
			xml.AddChildElemEx( _T("Contoured"),m_bContoured);
			xml.AddChildElemEx( _T("Shadow"),m_bShadowing);

			if (m_textFormat.IsVisible())
			{
				xml.AddChildElemEx(_T("Annotation"));
				xml.IntoElem();
					xml.AddChildElemEx(_T("XFirst"),m_bTextXFirst);
					m_textFormat.SerializeXML(ar);
				xml.OutOfElem();
			}	

		xml.OutOfElem();
	}
	else
	{
		if  (!xml.FindChildElem(szTag))
				return;

		xml.IntoElem();

			/////////////////////////////////////////////////////////
			// loading base class
			CPGLObject::SerializeXML(ar);

			xml.FindGetChildData( _T("LineWidth"), m_dLineWidth);
			xml.FindGetChildData( _T("LineDashing"), m_sLineDashing);
			xml.FindGetChildData( _T("Radius"), m_dRadius);
			xml.FindGetChildData( _T("Phase"), m_dPhase);
			xml.FindGetChildData( _T("Filled"), m_bFilled);
			xml.FindGetChildData( _T("Contoured"),m_bContoured);
			xml.FindGetChildData( _T("Shadow"),m_bShadowing);

			xml.ResetChildPos();
			if ( xml.FindChildElem(_T("Annotation")) )
			{
				xml.IntoElem();
					xml.FindGetChildData(_T("XFirst"), m_bTextXFirst);
					xml.ResetChildPos();
					m_textFormat.SerializeXML(ar);
				xml.OutOfElem();
			}
			else
				m_textFormat.Hide();
		xml.OutOfElem();
	}
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPGLMarker::CPGLMarker(const CPGLColor& _color, const CPGLColor& _FillColor, double dRadius, bool bFilled)
:CPGLObject(_color,_FillColor),
m_dLineWidth(2),m_sLineDashing(_T("")),m_dRadius(dRadius),m_dPhase(0),m_bFilled(bFilled), 
m_bTextXFirst(true), m_bContoured(true), m_bShadowing(false),
m_textFormat(_T("(%2.2g,%2.2g)") )
{
	m_textFormat.SetAlign( gfxinterface::TextAlignmentLeft);
	m_textFormat.Hide();

	PreparePropertyMap();
}

CPGLMarker& CPGLMarker::operator = ( const CPGLMarker& m)
{
	if (this != &m)
	{
		this->CPGLObject::operator =(m);

		m_dLineWidth = m.m_dLineWidth;
		m_sLineDashing = m.m_sLineDashing;
		m_dRadius = m.m_dRadius;
		m_dPhase = m.m_dPhase;
		m_bFilled = m.m_bFilled;
		m_bContoured = m.m_bContoured;
		m_bShadowing = m.m_bShadowing;
		m_bTextXFirst = m.m_bTextXFirst;
		m_textFormat = m.m_textFormat;
	}

	return *this;
}

CPGLMarker::~CPGLMarker()
{

}

void CPGLMarker::PlotGfx(gfxinterface::CGfxInterface& gfx, CPGLDataPtr pDataX, CPGLDataPtr pDataY)
{
	const UINT n =__min( pDataX->size(), pDataY->size());

	if (!pDataX || !pDataY || n==0)
		return;
	
	// drawing text...
	if (m_textFormat.IsVisible())
	{
		std::vector<std::_tstring> vStrings(n);
		std::vector<gfxinterface::SPointD> vPoints(n);
		CString str;
		
		for (UINT i=0;i<n;i++)
		{
			vPoints[i].x=(*pDataX)[i];
			vPoints[i].y=(*pDataY)[i];
			if (m_bTextXFirst)
				str.Format( m_textFormat.GetString(), vPoints[i].x, vPoints[i].y);
			else
				str.Format( m_textFormat.GetString(), vPoints[i].y, vPoints[i].x);
	
			vStrings[i]=str;
		}

		m_textFormat.CPGLObject::PlotGfx(gfx);
		gfx.DrawTextStrip( vPoints, vStrings, m_textFormat.GetAlign(), m_textFormat.GetAngle());
	}

	CPGLObject::PlotGfx(gfx);
}

void CPGLMarker::PlotLegendGfx(gfxinterface::CGfxInterface& gfx, float x, float y)
{
	CPGLObject::PlotGfx(gfx);
}

DWORD CPGLMarker::GetLineType() const
{
	using namespace gfxinterface;

	DWORD eLineType = 0;

	if (m_bFilled)
		eLineType |= LineTypeFilled;

	if (!m_bContoured)
		eLineType |= LineTypeNoContour;

	if (m_bShadowing)
		eLineType |= LineTypeShadow;

	return eLineType;
}


void CPGLMarker::PreparePropertyMap()
{
	using namespace std;

	static bool bLoaded(false);
	
	if (bLoaded)
		return;
	bLoaded=true;	

	CPGLObject::PreparePropertyMap();

	m_mProps[_T("Marker.linewidth")]=PropertyPair(MarkerPropLineWidth, _T("linewidth: Line width (pixels)"));
	m_mProps[_T("Marker.linedash")]=PropertyPair(MarkerPropLineDash, _T("linedash: Dash pattern"));
	m_mProps[_T("Marker.contour")]=PropertyPair(MarkerPropContoured, _T("contour: Contoured marker"));
	m_mProps[_T("Marker.shadow")]=PropertyPair(MarkerPropShadowing, _T("shadow: Shadowing state"));
	m_mProps[_T("Marker.filled")]=PropertyPair(MarkerPropFilled, _T("filled: Filled state"));
	m_mProps[_T("Marker.radius")]=PropertyPair(MarkerPropRadius, _T("radius: Radius (pixels)"));
	m_mProps[_T("Marker.phase")]=PropertyPair(MarkerPropPhase, _T("phase: Phase (radians)"));
	m_mProps[_T("Marker.xfirst")]=PropertyPair(MarkerPropXFirst, _T("xfirst: X first state"));
}

bool CPGLMarker::SetProperty( LPCTSTR szProp, LPCTSTR szValue)
{
	if (CPGLObject::SetProperty(szProp, szValue))
		return true;

	CString sv(szValue);
	sv.MakeLower();

	float f;
	switch( StringToMarkerProp( szProp ) )
	{
	case MarkerPropRadius:
		if (_stscanf(sv, _T("%f"), &f)==1)
			SetRadius(f);
		return true;
	case MarkerPropPhase:
		if (_stscanf(sv, _T("%f"), &f)==1)
			SetPhase(f);
		return true;
	case MarkerPropLineWidth:
		if (_stscanf(sv, _T("%f"), &f)==1)
			SetLineWidth(f);
		return true;
	case MarkerPropLineDash:
		SetLineDashing(sv);
		return true;
	case MarkerPropContoured:
		SetContoured( !(sv==_T("off") || sv==_T("false")) );
		return true;
	case MarkerPropShadowing:
		SetShadowing( !(sv==_T("off") || sv==_T("false")) );
		return true;
	case MarkerPropFilled:
		SetFilled( !(sv==_T("off") || sv==_T("false")) );
		return true;
	case MarkerPropXFirst:
		SetTextXFirst( !(sv==_T("off") || sv==_T("false")) );
		return true;
	default:
		return false;
	};
}

bool CPGLMarker::Get( LPCTSTR szProp, CString& str)
{
	if(CPGLObject::Get(szProp, str))
		return true;

	switch( StringToMarkerProp( szProp ))
	{
	case MarkerPropRadius:
		str.Format(_T("%g"), GetRadius());
		return true;
	case MarkerPropPhase:
		str.Format(_T("%g"), GetPhase());
		return true;
	case MarkerPropLineWidth:
		str.Format(_T("%g"), GetLineWidth());
		return true;
	case MarkerPropLineDash:
		str=GetLineDashing();
		return true;
	case MarkerPropContoured:
		str=(IsContoured()) ? _T("true") : _T("false");
		return true;
	case MarkerPropShadowing:
		str=(IsShadowing()) ? _T("true") : _T("false");
		return true;
	case MarkerPropFilled:
		str=(IsFilled()) ? _T("true") : _T("false");
		return true;
	case MarkerPropXFirst:
		str=(IsTextXFirst()) ? _T("true") : _T("false");
		return true;
	default:
		return false;
	};
}
